#pragma once
#include <iostream>
#include <map>
#include <functional>
#include <log.h>
#include <system.h>
#include "./media/streammanger.h"
#include "./configmanger/systemconfig.h"
#include "./media/streammq.h"
#include "./media/type.h"
// 导入ffmpeg相关头文件
extern "C"
{
#include "libavdevice/avdevice.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/imgutils.h"
}


struct Stream
{
	Media::StreamManger* stream = nullptr;
	Media::StreamMQ* hls_mq = nullptr;
	Media::StreamMQ* flv_mq = nullptr;
	Buffer::RingBuffer<std::shared_ptr<Media::StreamPacket> >* hls_buffer = nullptr;

	Buffer::RingBuffer<std::shared_ptr<Media::StreamPacket> >* flv_buffer = nullptr;
};

std::map<std::string, std::function<void(void)> > commond_map;
std::list< Stream > all_stream;


bool load()
{
	// 启动任务管理
	std::string system_config_path = System::Path::getRunningPath() + "config" + System::Path::getSubSymbol() + "monitor.json";
	// 解析配置文件
	Config::SystemConfig system_config(system_config_path);
	if (!system_config.paser())
	{
		Log::printError(system_config_path + " 解析失败程序即将退出!");
		system("pause");
		return false;
	}
	// 解析成功获取解析后的结果
	auto system_param = system_config.getSystemConfigParam();
	// rabbitmq地址
	std::string rabbitmq_host = system_param.rabbitmq_config.user + ":"
		+ system_param.rabbitmq_config.password
		+ "@"
		+ system_param.rabbitmq_config.ip
		+ ":"
		+ std::to_string(system_param.rabbitmq_config.port);


	for (auto it = system_param.stream_list.begin();
		it != system_param.stream_list.end();
		it++)
	{
		Stream node_stream;
		//源流url地址
		std::string src_url = it->url;
		Media::StreamManger* stream = new Media::StreamManger(src_url);
		node_stream.stream = stream;
		// 初始化hls

		{

			Buffer::RingBuffer<std::shared_ptr<Media::StreamPacket> >* hls_buffer = new Buffer::RingBuffer<std::shared_ptr<Media::StreamPacket> >(1024 * 2);
			node_stream.hls_buffer = hls_buffer;
			Media::StreamMQ* hls_mq = new Media::StreamMQ();
			node_stream.hls_mq = hls_mq;
			Media::HLSParam hls_param(it->hls_route,
				system_param.hls_config.ts_time,
				system_param.hls_config.ts_count,
				system_param.hls_config.ts_count_max,
				hls_buffer);

			hls_mq->connect(rabbitmq_host,
				"HLS",
				"hls_create_node [" + it->hls_route + "/index.m3u8]",
				hls_buffer);
			stream->setHLSParam(hls_param);
		}

		// 初始化flv
		if(1)
		{
			std::string flv_route = it->flv_route + "/live.flv";
			Buffer::RingBuffer<std::shared_ptr<Media::StreamPacket> >* flv_buffer = new Buffer::RingBuffer<std::shared_ptr<Media::StreamPacket> >(1024 * 2);
			node_stream.flv_buffer = flv_buffer;
			Media::StreamMQ* flv_mq = new Media::StreamMQ();
			node_stream.flv_mq = flv_mq;
			flv_mq->connect(rabbitmq_host,
				"FLV",
				"flv_create_node [" + flv_route + "]",
				flv_buffer);
			Media::FLVParam flv_param(flv_route, flv_buffer);
			stream->setFLVParam(flv_param);
		}

		stream->start();
		all_stream.push_back(node_stream);
	}
	return true;
}


void registerCommond()
{
	commond_map["help"] = []() {
		std::cout << "********************" << std::endl;
		std::cout << "ol : 打开日志" << std::endl;
		std::cout << "cl : 关闭日志" << std::endl;
		std::cout << "close : 关闭串流" << std::endl;
		//std::cout << "psc : 打印拉流重拉次数" << std::endl;
		//std::cout << "pse : 打印拉流重失败次数" << std::endl;
		std::cout << "help:帮助" << std::endl;
		std::cout << "********************" << std::endl;
	};

	commond_map["ol"] = []() {
		av_log_set_level(AV_LOG_WARNING);
		// 打开日志打印
		Log::setPrint(true);
	};

	commond_map["cl"] = []() {
		// 打开日志打印
		Log::setPrint(false);
		av_log_set_level(AV_LOG_QUIET);
	};

	commond_map["stop"] = []() {
		for (auto it = all_stream.begin();
			it != all_stream.end();
			it++)
		{
			// 码流先停止
			it->stream->stop();
			it->flv_mq->stop();
			it->hls_mq->stop();

			delete it->flv_buffer;
			delete it->hls_buffer;
			delete it->stream;
			delete it->flv_mq;
			delete it->hls_mq;
		}
		all_stream.clear();
	};

	commond_map["start"] = []() {

		if (!load())
		{
			exit(1);
		}
	};

}

int main()
{
	system("chcp 65001");
	//1.注册组件
	avdevice_register_all();
	registerCommond();
	Log::setPrint(true);

	if (!load())
	{
		return 0;
	}
	

	std::string commond;
	while (std::cin >> commond)
	{
		auto it = commond_map.find(commond);
		if (it != commond_map.end())
		{
			it->second();
		}
		else
		{
			Log::printInfo("命令\"" + commond + "\"不支持");
		}
	}
	return 0;
}